package cn.edu.zut.score.core.util;

import io.swagger.annotations.ApiModel;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;

/**
 * @author zby
 */

@ApiModel(description = "日期工具类封装")
public class DateUtils {
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    public static final String YYYYMMDD = "yyyyMMdd";

    public static final String YYYYMMddHHmmss = "YYYYMMddHHmmss";

    public static final String HHmmss = "HHmmss";

    public static final String YYYYMM = "yyyyMM";

    public static final DateTimeFormatter YYYY_MM_DD_HH_MM_SS_DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern(YYYY_MM_DD_HH_MM_SS);
    public static final DateTimeFormatter YYYYMMDD_DATE_FORMATTER = DateTimeFormatter.ofPattern(YYYYMMDD);
    public static final DateTimeFormatter HHmmss_TIME_FORMATTER = DateTimeFormatter.ofPattern(HHmmss);
    public static final DateTimeFormatter YYYYMM_DATE_FORMATTER = DateTimeFormatter.ofPattern(YYYYMM);

    private DateUtils() {
    }

    /**
     * @Param [date, hour] [指定的时间, 多少小时后]
     * @Return java.util.Date [添加后的时间]
     * @Author zby
     * @Description 从给定的date，加上hour小时 求指定date时间后hour小时的时间
     */
    public static Date addExtraHour(Date date, int hour) {
        Calendar cal = Calendar.getInstance();
        if (date != null) {
            cal.setTime(date);
        }
        cal.add(Calendar.HOUR_OF_DAY, hour);
        return cal.getTime();
    }

    /**
     * @Param [date, second] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 当前时间 减去 多少秒。
     */
    public static String minusExtraSecond(Date date, int second) {
        Date tempDate = new Date(date.getTime() - second * 1000L);
        return format(tempDate, YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * @Param [date, increase] []
     * @Return java.util.Date []
     * @Author zby
     * @Description 从给定的date，加上increase天
     */
    public static Date increaseDay2Date(Date date, int increase) {
        Calendar cal = Calendar.getInstance();
        if (date != null) {
            cal.setTime(date);
        }
        cal.add(Calendar.DAY_OF_MONTH, increase);
        return cal.getTime();
    }

    /**
     * @Param [strDate, format] []
     * @Return java.util.Date []
     * @Author zby
     * @Description 把字符串日期默认转换为yyyy-mm-dd格式的Data对象
     */
    public static Date format(String strDate, String format) {
        Date d;
        if (null == strDate || "".equals(strDate)) {
            return null;
        } else {
            try {
                d = getFormatter(format).parse(strDate);
            } catch (ParseException pex) {
                return null;
            }
            return d;
        }
    }

    /**
     * @Param [parttern] []
     * @Return java.text.SimpleDateFormat [一个简单的日期格式化对象]
     * @Author zby
     * @Description 获取一个简单的日期格式化对象
     */
    private static SimpleDateFormat getFormatter(String parttern) {
        return new SimpleDateFormat(parttern);
    }

    /**
     * @Param [month, dateFormat] [要查询的日期（如果为null 则默认为当前月）, 返回日期的格式（如果为null 则返回yyyy-MM-dd 格式结果）]
     * @Return java.util.List<java.lang.String> []
     * @Author zby
     * @Description 获取month所在月的所有天
     */
    public static List<String> getAllDaysOfMonthInString(Date month, DateFormat dateFormat) {
        List<String> rs = new ArrayList<>();
        DateFormat df = null;
        if (null == dateFormat) {
            df = new SimpleDateFormat("yyyy-MM-dd");
        }
        Calendar cad = Calendar.getInstance();
        if (null != month) {
            cad.setTime(month);
        }
        int dayMonth = cad.getActualMaximum(Calendar.DAY_OF_MONTH); // 获取当月天数
        for (int i = 0; i < dayMonth; i++) {
            cad.set(Calendar.DAY_OF_MONTH, i + 1);
            assert df != null;
            rs.add(df.format(cad.getTime()));
        }
        return rs;
    }

    /**
     * @Param [month] [要查询的日期（如果为null 则默认为当前月）]
     * @Return java.util.List<java.util.Date> [日期List]
     * @Author zby
     * @Description 获取month所在月的所有天
     */
    public static List<Date> getAllDaysOfMonth(Date month) {
        List<Date> rs = new ArrayList<>();
        Calendar cad = Calendar.getInstance();
        if (null != month) {
            cad.setTime(month);
        }
        int dayMonth = cad.getActualMaximum(Calendar.DAY_OF_MONTH); // 获取当月天数
        for (int i = 0; i < dayMonth; i++) {
            cad.set(Calendar.DAY_OF_MONTH, i + 1);
            rs.add(cad.getTime());

        }
        return rs;
    }

    /**
     * @Param [begin, end, dateFormat] []
     * @Return java.util.List<java.lang.String> [如果为null 则返回yyyy-MM-dd格式的日期]
     * @Author zby
     * @Description 获取指定日期区间所有天
     */
    public static List<String> getSpecifyDaysOfMonthInString(Date begin, Date end, DateFormat dateFormat) {
        DateFormat df = null;
        if (null == dateFormat) {
            df = new SimpleDateFormat("yyyy-MM-dd");
        }
        List<String> rs = new ArrayList<>();
        List<Date> tmplist = getSpecifyDaysOfMonth(begin, end);
        for (Date date : tmplist) {
            assert df != null;
            rs.add(df.format(date));
        }
        return rs;
    }

    /**
     * @Param [begin, end] []
     * @Return java.util.List<java.util.Date> []
     * @Author zby
     * @Description 获取指定日期区间所有天
     */
    public static List<Date> getSpecifyDaysOfMonth(Date begin, Date end) {
        List<Date> rs = new ArrayList<>();
        Calendar cad = Calendar.getInstance();
        int dayMonth;
        if (null == begin) {// 设置开始日期为指定日期
            cad.set(Calendar.DAY_OF_MONTH, 1);// 设置开始日期为当前月的第一天
            begin = cad.getTime();
        }
        cad.setTime(begin);
        if (null == end) {// 如果结束日期为空 ，设置结束日期为下月的第一天
            dayMonth = cad.getActualMaximum(Calendar.DAY_OF_MONTH); // 获取当月天数
            cad.set(Calendar.DAY_OF_MONTH, dayMonth + 1);
            end = cad.getTime();
        }
        cad.set(Calendar.DAY_OF_MONTH, 1);// 设置开始日期为当前月的第一天
        Date tmp;
        int i = 1;
        while (true) {
            cad.set(Calendar.DAY_OF_MONTH, i);
            i++;
            tmp = cad.getTime();
            if (tmp.before(end)) {
                rs.add(cad.getTime());
            } else {
                break;
            }
        }
        return rs;
    }

    /**
     * @Param [] []
     * @Return java.util.Date [一个包含年月日的<code>Date</code>型日期]
     * @Author zby
     * @Description 获取当前日期
     */
    public static synchronized Date getCurrDate() {
        Calendar calendar = Calendar.getInstance();
        return calendar.getTime();
    }

    /**
     * @Param [date, pattern] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 按指定格式格式化日期
     */
    public static String format(Date date, String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        return dateFormat.format(date);
    }

    /**
     * @Param [] []
     * @Return java.lang.String [一个包含年月日时分秒的<code>String</code>型日期。yyyy-MM-dd hh:mm:ss]
     * @Author zby
     * @Description 获取当前完整时间, 样式: yyyy－MM－dd hh:mm:ss
     */
    public static String getCurrDateTimeStr() {
        return format(getCurrDate(), YYYY_MM_DD_HH_MM_SS);
    }

    /**
     * @Param [specifiedDay, formatStr] [specifiedDay YYYY_MM_DD_HH_MM_SS 格式]
     * @Return java.lang.String []
     * @Author zby
     * @Description 获得指定日期的前一天
     */
    public static String getSpecifiedDayBefore(String specifiedDay, String formatStr) {// 可以用new
        // Date().toLocalString()传递参数
        Calendar c = Calendar.getInstance();
        Date date = null;
        try {
            date = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS).parse(specifiedDay);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        assert date != null;
        c.setTime(date);
        int day = c.get(Calendar.DATE);
        c.set(Calendar.DATE, day - 1);
        return new SimpleDateFormat(formatStr).format(c.getTime());
    }

    /**
     * @Param [specifiedDay, formatStr] [, ]
     * @Return java.lang.String [日期类型]
     * @Author zby
     * @Description 获得指定日期的后一天
     */
    public static String getSpecifiedDayAfter(String specifiedDay, String formatStr) {
        Calendar c = Calendar.getInstance();
        Date date = null;
        try {
            date = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS).parse(specifiedDay);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        assert date != null;
        c.setTime(date);
        int day = c.get(Calendar.DATE);
        c.set(Calendar.DATE, day + 1);
        return new SimpleDateFormat(formatStr).format(c.getTime());
    }

    /**
     * @Param [] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取本周第一天的日期
     */
    public static String getWeekFirstDay() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cal = Calendar.getInstance();
        int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK) - 2;
        cal.add(Calendar.DATE, -dayOfWeek);
        return sdf.format(cal.getTime());
    }

    /**
     * @Param [] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取当前月的第一天
     */
    public static String getCurrentMonthFirstDay() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 当前月的第一天
        cal.set(GregorianCalendar.DAY_OF_MONTH, 1);
        Date beginTime = cal.getTime();
        return sdf.format(beginTime);
    }

    /**
     * @Param [] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取昨天开始时间
     */
    public static String getYesterdayStart() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime());
    }

    /**
     * @Param [] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取今年结束
     */
    public static String getYesterdayEnd() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime()) + " 23:59:59";
    }

    /**
     * @Param [] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取今天开始
     */
    public static String getCurrDayStart() {
        Calendar cal = Calendar.getInstance();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime());
    }

    /**
     * @Param [month] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 取指定月份的第一天
     */
    public static String getStartDayWithMonth(String month) throws ParseException {
        Calendar calendar = new GregorianCalendar();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat mf = new SimpleDateFormat("yyyy-MM");
        Date date = mf.parse(month);
        calendar.setTime(date);
        calendar.add(Calendar.DATE, 0);// 因为格式化时默认了DATE为本月第一天所以此处为0
        return sdf.format(calendar.getTime());
    }

    /**
     * @Param [month] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 获取指定月份的最后一天
     */
    public static String getEndDayWithMonth(String month) throws ParseException {
        Calendar calendar = new GregorianCalendar();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat mf = new SimpleDateFormat("yyyy-MM");
        Date date = mf.parse(month);
        calendar.setTime(date);
        calendar.roll(Calendar.DATE, -1);// api解释roll()：向指定日历字段添加指定（有符号的）时间量，不更改更大的字段
        return sdf.format(calendar.getTime());
    }

    /**
     * @Param [dateStr] []
     * @Return java.lang.String []
     * @Author zby
     * @Description 格式化日期（字符串）为年月日格式
     */
    public static String formatYearMonthDay(String dateStr) throws ParseException {
        if (StringUtils.isNotBlank(dateStr)) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Date date = sdf.parse(dateStr);
            return sdf.format(date);
        } else {
            return "";
        }
    }

    /**
     * @Param [dateStr] []
     * @Return int []
     * @Author zby
     * @Description 根据时间 yyyy-MM-dd 获取该日期是本月第几周
     */
    public static int getWeekIndexOfMonth(String dateStr) throws ParseException {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date = sdf.parse(dateStr);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.get(Calendar.WEEK_OF_MONTH);
    }

    /**
     * @Param [designationTime] []
     * @Return int []
     * @Author zby
     * @Description 获取当前时间到指定时间距离多少秒
     */
    public static int getSecondToDesignationTime(String designationTime) {
        // 24小时制
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date toDate;
        try {
            toDate = dateFormat.parse(designationTime);
            return (int) ((toDate.getTime() - dateFormat.parse(DateUtils.getCurrDateTimeStr()).getTime()) / 1000);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * @Param [startDate, endDate] []
     * @Return long []
     * @Author zby
     * @Description 计算两个日期之间的间隔天数
     */
    public static long startToEnd(Date startDate, Date endDate) {
        String[] startStr = new SimpleDateFormat("yyyy-MM-dd").format(startDate).split("-");
        String[] endStr = new SimpleDateFormat("yyyy-MM-dd").format(endDate).split("-");
        int startYear = Integer.parseInt(startStr[0]);
        int startMonth = Integer.parseInt(startStr[1]);
        int startDay = Integer.parseInt(startStr[2]);
        int endYear = Integer.parseInt(endStr[0]);
        int endMonth = Integer.parseInt(endStr[1]);
        int endDay = Integer.parseInt(endStr[2]);
        LocalDate endLocalDate = LocalDate.of(endYear, endMonth, endDay);
        LocalDate startLocalDate = LocalDate.of(startYear, startMonth, startDay);
        return startLocalDate.until(endLocalDate, ChronoUnit.DAYS);
    }

    /**
     * @Param [] []
     * @Return int []
     * @Author zby
     * @Description 获取现在年份
     */
    public static int getYear() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.YEAR);
    }

    /**
     * @Param [] []
     * @Return int []
     * @Author zby
     * @Description 获取现在月份
     */
    public static int getMonth() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.MONTH) + 1;
    }

    /**
     * @Param [] []
     * @Return int []
     * @Author zby
     * @Description 获取现在提天数
     */
    public static int getDay() {
        Calendar cal = Calendar.getInstance();
        return cal.get(Calendar.DATE);
    }

    /**
     * @Param [localDateTime] []
     * @Return java.util.Date []
     * @Author zby
     * @Description LocalDateTime类型日期转换为Date类型
     */
    public static Date localDateTime2Date(LocalDateTime localDateTime) {
        if (localDateTime != null) {
            return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
        } else {
            return null;
        }
    }

    /**
     * @Param [localDateTime] []
     * @Return java.util.Date []
     * @Author zby
     * @Description LocalDate类型日期转换为Date类型
     */
    public static Date localDate2Date(LocalDate localDate) {
        if (localDate != null) {
            return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
        } else {
            return null;
        }
    }

    /**
     * @Param [localDateTime] []
     * @Return java.util.Date []
     * @Author zby
     * @Description Date类型日期转换为LocalDate类型
     */
    public static LocalDate date2LocalDate(Date date) {
        if (date != null) {
            LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
            return localDateTime.toLocalDate();
        }
        return null;
    }

    /**
     * @Param [localDateTime] []
     * @Return java.util.Date []
     * @Author zby
     * @Description Date类型日期转换为LocalDateTime类型
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        if (date != null) {
            return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
        }
        return null;
    }
}
